package com.utry.netty.client;

import android.util.Log;

import com.utry.netty.intf.MessageClientCallback;

import java.net.InetSocketAddress;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.timeout.IdleStateHandler;


public class NettyClient {

    private static final String TAG = "NettyClient";
//    private final int PORT = 18000;
            private final int PORT = 7101;
//    private final int PORT = 7010;
//    private final String IP = "192.168.2.58";
    private final String IP = "192.168.10.231";
//        private final String IP = "192.168.8.156";
    private static NettyClient nettyClient;
    private Channel channel;
    private ChannelFuture channelFuture;
    private MessageClientCallback messageClientCallback;

    public static NettyClient getInstance() {
        if (nettyClient == null) {
            nettyClient = new NettyClient();
        }
        return nettyClient;
    }

    /**
     * 需要在子线程中发起连接
     */
    private NettyClient() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                connect();
            }
        }).start();
    }

    /**
     * 获取与服务端的连接
     */
    public static Channel getChannel() {
        if (nettyClient == null) {
            return null;
        }
        return nettyClient.channel;
    }

    /**
     * 连接服务端
     */
    public void connect() {
        try {
            NioEventLoopGroup group = new NioEventLoopGroup();
            Bootstrap bootstrap = new Bootstrap()
                    // 指定channel类型
                    .channel(NioSocketChannel.class)
                    // 指定EventLoopGroup
                    .group(group)
                    // 指定Handler
                    .handler(new ChannelInitializer<SocketChannel>() {
                        //分隔符
                        ByteBuf delimiter = Unpooled.copiedBuffer("$".getBytes());

                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            ChannelPipeline pipeline = socketChannel.pipeline();
                            pipeline.addLast(new IdleStateHandler(10, 0, 2));
                            //解决粘包
//                            pipeline.addLast(new DelimiterBasedFrameDecoder(65535, delimiter));
                            //添加发送数据编码器
//                            pipeline.addLast(new ClientEncoder());
//                            //添加收到的数据解码器
//                            pipeline.addLast(new ClientDecoder());

                            //解码
                            // 这里将LengthFieldBasedFrameDecoder添加到pipeline的首位，因为其需要对接收到的数据
                            // 进行长度字段解码，这里也会对数据进行粘包和拆包处理
                            pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 0, 2, 0, 2));
                            //编码
                            // LengthFieldPrepender是一个编码器，主要是在响应字节数据前面添加字节长度字段
                            pipeline.addLast(new LengthFieldPrepender(2));

                            // 对经过粘包和拆包处理之后的数据进行json反序列化，从而得到User对象
                            pipeline.addLast(new JsonDecoder());
                            // 对响应数据进行编码，主要是将User对象序列化为json
                            pipeline.addLast(new JsonEncoder());
                            //添加数据处理器
                            pipeline.addLast(new ClientHandler(NettyClient.this, messageClientCallback));
                        }
                    });
            // 连接到服务端
            channelFuture = bootstrap.connect(new InetSocketAddress(IP, PORT));
            // 添加连接状态监听
            channelFuture.addListener(new ConnectListener(this));
            //获取连接通道
            channel = channelFuture.sync().channel();
            if (null != messageClientCallback) {
                messageClientCallback.messageClientCallback("连接成功");
            }

        } catch (Exception e) {
            if (null != messageClientCallback) {
                messageClientCallback.messageClientCallback("连接失败");
            }
            Log.e(TAG, "连接失败：" + e.getMessage());
            e.printStackTrace();
        }

    }

    public void disConnect() {
        if (channelFuture != null && channelFuture.channel() != null) {
            channelFuture.channel().close();
        }
    }

    public void destroy() {
        if (channelFuture != null && channelFuture.channel() != null) {
            channelFuture.channel().close();
            channelFuture.channel().eventLoop().shutdownGracefully();
        }
    }

    public void setMessageClientCallback(MessageClientCallback messageClientCallback) {
        this.messageClientCallback = messageClientCallback;
    }
}
